package com.slipper.bpmn.dealer.support;

import com.slipper.constants.Constants;
import com.slipper.constants.FlowConstants;
import com.slipper.bpmn.BpmnEngine;
import com.slipper.system.employee.bo.EmployeeBO;
import com.slipper.system.employee.service.EmployeeService;
import com.slipper.system.flow.bo.*;
import com.slipper.system.flow.service.*;
import com.slipper.util.Tool;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import com.slipper.bpmn.vo.BpmnVO;
import com.slipper.bpmn.dealer.INodeDealer;

/**
 * 人工节点处理器
 */
@Component
public class ManuallyNodeDealer implements INodeDealer {
    @Resource
    private FlowInstNodeService flowInstNodeService;
    @Resource
    private BpmnEngine bpmnEngine;
    @Resource
    private FlowPendingService flowPendingService;
    @Resource
    private EmployeeService employeeService;

    @Override
    public String[] getTypes() {
        return new String[] { "10" };
    }

    @Override
    public FlowInstNodeBO doDeal(
            int dealCnt,
            boolean finished,
            FlowNodeBO flowNode,
            FlowInstBO flowInst,
            FlowInstNodeBO preInstNode,
            FlowInstNodeBO currInstNode,
            BpmnVO vo) {
        this.checkDealCntAssert(dealCnt);
        flowInst.setCurrNodeNames(flowNode.getName());
        
        if (finished) {
            currInstNode = this.finished(dealCnt, flowNode, flowInst, preInstNode, currInstNode, vo);
            bpmnEngine.next(dealCnt + 1, flowNode, flowInst, currInstNode);
        } else {
            BpmnVO bpmnVO = vo.cloneValue();
            currInstNode = this.createInstData(dealCnt, flowNode, flowInst, preInstNode, bpmnVO, false);
        }

        return currInstNode;
    }

    private FlowInstNodeBO finished(
            int dealCnt,
            FlowNodeBO flowNode,
            FlowInstBO flowInst,
            FlowInstNodeBO preInstNode,
            FlowInstNodeBO currInstNode,
            BpmnVO vo) {
        if (currInstNode == null) {
            currInstNode = this.createInstData(dealCnt, flowNode, flowInst, preInstNode, vo, true);
        } else {
            currInstNode = this.flowInstNodeService.queryBy(currInstNode.getId());
            if (FlowConstants.FlowInstNode.DEAL_STATUS_FINISHED.equals(currInstNode.getDealStatus())) {
                throw new RuntimeException("此流程待办已办理！");
            }

            currInstNode.setLineId(Tool.isBlank(flowNode.getInLineId()) ? currInstNode.getLineId() : flowNode.getInLineId());
            currInstNode.setDealManId(vo.getCurrEmpId());
            currInstNode.setDealOrgId(vo.getCurrOrgId());
            currInstNode.setEndTime(System.currentTimeMillis());
            currInstNode.setSubmitFlag(vo.getSubmitFlag());
            currInstNode.setSignatureId(vo.getSignatureId());
            currInstNode.setDealStatus(FlowConstants.FlowInstNode.DEAL_STATUS_FINISHED);
            this.flowInstNodeService.save(currInstNode);

            // 节点处理完成，设置待办为完成
            FlowPendingBO pendingQO = new FlowPendingBO();
            pendingQO.setInstNodeId(currInstNode.getId());
            pendingQO.setCurrManId(currInstNode.getDealManId());
            pendingQO.setCurrOrgId(currInstNode.getDealOrgId());
            FlowPendingBO pending = this.flowPendingService.queryByOne(pendingQO);
            if (pending != null) {
                pending.setCurrManId(vo.getCurrEmpId());
                pending.setCurrOrgId(vo.getCurrOrgId());
                pending.setFinishedTime(System.currentTimeMillis());
                pending.setStatus(FlowConstants.FlowPending.STATUS_FINISHED);
                this.flowPendingService.save(pending);
            }
        }
        return currInstNode;
    }

    public FlowInstNodeBO createInstData(
            int dealCnt,
            FlowNodeBO flowNode,
            FlowInstBO flowInst,
            FlowInstNodeBO preInstNode,
            BpmnVO vo,
            boolean finished) {
        String dealManIds = vo.getCurrEmpId();
        if (Tool.isBlank(dealManIds)) throw new RuntimeException("无法确定下一环节处理人！");

        FlowInstNodeBO flowInstNodeBO = null;
        for(String dealManId : dealManIds.split(",")) {
            if (Tool.isBlank(dealManId)) continue;

            String dealOrgId;
            if (dealManId.contains("@")) {
                String[] dealIds = dealManId.split("@");
                dealOrgId = dealIds[0];
                dealManId = dealIds[1];
            } else {
                EmployeeBO employeeBO = employeeService.queryBy(dealManId);
                if (employeeBO == null) throw new RuntimeException("下一节点处理人不存在！");
                dealOrgId = employeeBO.getOrganizationId();
            }

            FlowInstNodeBO flowInstNode = new FlowInstNodeBO();
            flowInstNode.setInstId(flowInst.getId());
            flowInstNode.setPreInstNodeId(preInstNode == null ? null : preInstNode.getId());
            flowInstNode.setLineId(flowNode.getInLineId());
            flowInstNode.setCurrFlowNodeId(flowNode.getId());
            flowInstNode.setDealManId(dealManId);
            flowInstNode.setDealOrgId(dealOrgId);
            flowInstNode.setStartTime(System.currentTimeMillis());
            flowInstNode.setSubmitFlag(vo.getSubmitFlag());
            flowInstNode.setUpdateTime(System.currentTimeMillis());
            flowInstNode.setCreateTime(System.currentTimeMillis());

            if (!finished) {
                flowInstNode.setDealStatus(FlowConstants.FlowInstNode.DEAL_STATUS_PENDING);
            } else {
                flowInstNode.setEndTime(System.currentTimeMillis());
                flowInstNode.setDealStatus(FlowConstants.FlowInstNode.DEAL_STATUS_FINISHED);
            }

            flowInstNodeService.save(flowInstNode);

            FlowPendingBO pending = new FlowPendingBO();
            pending.setFlowId(flowNode.getFlowId());
            pending.setNodeId(flowNode.getId());
            pending.setInstId(flowInst.getId());
            pending.setInstNodeId(flowInstNode.getId());
            pending.setPendingTime(System.currentTimeMillis());
            pending.setCurrManId(flowInstNode.getDealManId());
            pending.setCurrOrgId(flowInstNode.getDealOrgId());
            pending.setTitle(flowInst.getTitle());
            pending.setFinishedTime(finished ? System.currentTimeMillis() : null);
            pending.setIfRead(Constants.NO);
            pending.setStatus(finished ? FlowConstants.FlowPending.STATUS_FINISHED : FlowConstants.FlowPending.STATUS_PENDING);
            pending.setSettlorId(flowInstNode.getSettlorId());
            pending.setSendManId(preInstNode == null ? flowInstNode.getDealManId() : preInstNode.getDealManId());
            pending.setCreateTime(System.currentTimeMillis());
            this.flowPendingService.save(pending);

            if (!finished && dealCnt >= 0) {
                sendMessage(flowNode, flowInst, pending.getCurrManId());
            }
            flowInstNodeBO = flowInstNode;
        }

        return flowInstNodeBO;
    }
}
